/**
 * <p>文件名:		BizUtils.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		周华彬(zhouhuabin@sinoiov.com, zhou_hua_bin@163.com)
*/

package com.caits.lbs.framework.utils;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.caits.lbs.framework.bean.common.ApiParam;
import com.caits.lbs.framework.utils.MD5;
import com.caits.lbs.framework.utils.SpringUtils;
import com.caits.lbs.framework.utils.StringUtils;
import com.caits.lbs.framework.utils.TimeUtils;

/**
 * <p>BizUtils</p>
 * <p>通用业务层工具类</p>
 *
 * @author		周华彬(zhouhuabin@sinoiov.com, zhou_hua_bin@163.com)
 * @version		0.0.0
 * <table style="border:1px solid gray;">
 * <tr>
 * <th width="100px">版本号</th><th width="100px">动作</th><th width="100px">修改人</th><th width="100px">修改时间</th>
 * </tr>
 * <!-- 以 Table 方式书写修改历史 -->
 * <tr>
 * <td>0.0.0</td><td>创建类</td><td>admin</td><td>2017年8月3日 下午3:29:45</td>
 * </tr>
 * <tr>
 * <td>XXX</td><td>XXX</td><td>XXX</td><td>XXX</td>
 * </tr>
 * </table>
 */
public abstract class BizUtils {

	private final static Logger LOG = LogManager.getLogger(BizUtils.class);

	public static Integer maxNum = 10000;
	public final static String NUMBER_FORMAT = "0000";
	/** 变量:当前序列号,类型:int */
	private static int serialNum;
	/** 变量:TODO,类型:String */
	private static String initDate;
	/**
	 * 生成当前的序列号 ,非线程安全
	 * @return 
	 * @return 返回String
	 */
	public static String buildDailySequenceID() {
		// if the date changed, recount the serial number from 0
		String callDate = TimeUtils.simpleDateFormat(new Date(),"yyyyMMdd");
		if (!callDate.equals(initDate)) {
			serialNum = 0;
			initDate = callDate;
		}
		// generate the ident
		String datetimeBody = TimeUtils.simpleDateFormat(new Date(), "yyyyMMddHHmmss");
		if (serialNum < maxNum) {
			serialNum++;
		} else {
			serialNum = 1;
		}
		DecimalFormat df = new DecimalFormat(NUMBER_FORMAT);
		String numTail = df.format(serialNum);
		StringBuilder sb = new StringBuilder();
		sb.append("1");
		sb.append(datetimeBody);
		sb.append(numTail);
		return sb.toString();
	}
	/**
	 * 生成指定位数的随机数 字
	 * @param num 生成的位数
	 * @return 返回String
	 */
	public static String buildValidateCode(int num) {
		Random random = new Random();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < num; i++) {
			int itmp = random.nextInt(10) + 48;
			char ctmp = (char) itmp;
			sb.append(ctmp);
		}
		return sb.toString();
	}
	/**
	 * 产生多位大写字母的随机串 
	 * @param length
	 * @return String
	 */
	public static String generateRandomUpperString(int length) {
		if(length<=0){
			return "";
		}
	    String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";  
	    Random random = new Random();
	    StringBuffer buf = new StringBuffer();  
	    for (int i = 0; i < length; i++) {  
	        int num = random.nextInt(26);  
	        buf.append(str.charAt(num));  
	    }  
	    return buf.toString();  
	}
	/**
	 * 组装支付中心业务订单号 
	 * @param cacheUser
	 * @return 
	 * @return 返回String
	 */
	public static String buildAccountWorkOrderNo(long uid,String prefix) {
		return prefix+uid+"_"+TimeUtils.simpleDateFormat(new Date(),"yyyyMMddHHmmsss")+generateRandomUpperString(2);
	}
	/**
	 * 过滤表情符号 
	 * @param str
	 * @return 返回String
	 */
	public static String filterEmojiStr(String str) {  
	        if(StringUtils.isNullOrBlank(str)){  
	            return str;  
	        }
	        String pattern="[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]";  
	        String reStr="";  
	        Pattern emoji=Pattern.compile(pattern);  
	        Matcher  emojiMatcher=emoji.matcher(str);  
	        str=emojiMatcher.replaceAll(reStr);  
	        return str;  
	    }
	/**
	 * @Description:把list转换为一个用逗号分隔的字符串
	 */
	public static String listToString(List<String> list, String sep) {
		StringBuilder sb = new StringBuilder();
		if (list != null && list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				if (i < list.size() - 1) {
					sb.append(list.get(i) + sep);
				} else {
					sb.append(list.get(i));
				}
			}
		}
		return sb.toString();
	}
	/**
	 * 解析出url参数中的键值对 
	 * @param URL
	 * @return 
	 */
	public static Map<String, String> parseURLRequestParameter(String URL) {
		Map<String, String> mapRequest = new HashMap<String, String>();
		String[] arrSplit = null;
		String strUrlParam = truncateUrlPrefix(URL);
		if (strUrlParam == null) {
			return mapRequest;
		}
		//每个键值为一组 
		arrSplit = strUrlParam.split("[&]");
		for (String strSplit : arrSplit) {
			String[] arrSplitEqual = null;
			arrSplitEqual = strSplit.split("[=]");
			//解析出键值 
			if (arrSplitEqual.length > 1) {
				//正确解析 
				mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
			} else {
				if (arrSplitEqual[0] != "") {
					//只有参数没有值，不加入 
					mapRequest.put(arrSplitEqual[0], "");
				}
			}
		}
		return mapRequest;
	}
	/**
	 * 去掉url中的?前的部分路径，留下请求参数部分 
	 * @param strURL
	 * @return 
	 */
	public static String truncateUrlPrefix(String strURL) {
		String strAllParam = null;
		String[] arrSplit = null;
		strURL = strURL.trim();
		arrSplit = strURL.split("[?]");
		if (strURL.length() > 1) {
			if (arrSplit.length > 1) {
				if (arrSplit[1] != null) {
					strAllParam = arrSplit[1];
				}
			}
		}
		return strAllParam;
	}
	
	/**
	 * 把urldata数据解析出文件类型 <br>
	 * RFC2397规范：<br>
	 * dataurl := "data:" [ mediatype ] [ ";base64" ] "," data<br>
	   mediatype := [ type "/" subtype ] *( ";" parameter )<br>
		data := *urlchar<br>
		parameter := attribute "=" value<br>
	 * @param data
	 * 		<p>
	 *  data:,<文本数据>	<br>
		data:text/plain,<文本数据>	<br>
		data:text/html,<HTML代码>	<br>
		data:text/html;base64,<base64编码的HTML代码><br>
		data:text/css,<CSS代码><br>
		data:text/css;base64,<base64编码的CSS代码><br>
		data:text/javascript,<Javascript代码><br>
		data:text/javascript;base64,<base64编码的Javascript代码><br>
		编码的gif图片数据<br>
		编码的png图片数据<br>
		编码的jpeg图片数据<br>
		编码的icon图片数据<br>
	 * </p>
	 * @return 返回Object
	 */
	public static String parseUrlDataFileType(String urlData){
		try{
			String ext = StringUtils.null2default(StringUtils.subStringBySatrtEndStr(urlData, "data:image/", ";"), "jpg");//图片后缀			
			if(StringUtils.notNullOrBlank(ext)){
				//编码的gif图片数据
				//编码的png图片数据
				if("jpeg".equalsIgnoreCase(ext)){//编码的jpeg图片数据
					ext = "jpg";
				} else if("x-icon".equalsIgnoreCase(ext)){//编码的icon图片数据
					ext = "ico";
				}
			}
			return ext;
		}catch(Exception e){
			LOG.error("解析数据类型异常urlData:"+urlData+",msg:"+e.getLocalizedMessage());
			return null;
		}
	}
	/**
	 * 空值安全转换 
	 * @param obj
	 * @param defaultStr
	 * @return 
	 * @return 返回String
	 */
	public static String nullSafeToString(Object obj,String defaultStr) {
		if (obj == null) {
			return defaultStr;
		}
		if (obj instanceof String) {
			return (String) obj;
		}
		String str = obj.toString();
		return (str != null ? str : "");
	}
	
	/**
	 * 返回字符串的默认长度
	 * 
	 * @param prefix
	 * @return
	 * @return 返回String
	 */
	public static String buildStringDefaultLength(String prefix,int mexLength) {
		return buildStringMaxLength(prefix, mexLength);
	}

	/**
	 * 返回字符串的最大长度
	 * 
	 * @param prefix
	 * @param length
	 * @return
	 */
	public static String buildStringMaxLength(String prefix, int length) {
		int printLength = Math.min(prefix.length(), length);
		return prefix.substring(0, printLength);
	}
	
	/**
	 * 输出指定行数的日志 
	 * @param ex
	 * @param lineNum
	 */
	public static void printExceptionLog(Throwable ex, int lineNum) {
		StackTraceElement[] stackArr = ex.getStackTrace();
		for (int i = 0; i < stackArr.length && i < lineNum; i++) {
			String errorMsg1 = stackArr[i].toString();
			LOG.error("at:{}", errorMsg1);
		}
	}
	/**
	 * 只打印5行异常信息到默认log
	 * 
	 * @param method
	 *            方法中文名称
	 * @param ex
	 */
	public static void printShortException(String method, Exception ex) {
		StackTraceElement[] stackArr = ex.getStackTrace();
		StringBuilder errorMsg1 = new StringBuilder(method);
		errorMsg1.append("处理异常,msg:").append(ex.getLocalizedMessage());
		for (int i = 0; i < Math.min(stackArr.length,5); i++) {
			errorMsg1.append("\r\n at:").append(stackArr[i].toString());
		}
		LOG.error(errorMsg1.toString());
	}
	/**
	 * 只打印5行异常信息到制定log
	 * @param	log	日志记录器
	 * @param method  方法中文名称
	 * @param ex	异常对象
	 */
	public static void printShortException(Logger log,String method, Exception ex) {
		StackTraceElement[] stackArr = ex.getStackTrace();
		StringBuilder errorMsg1 = new StringBuilder(method);
		errorMsg1.append("处理异常,msg:").append(ex.getLocalizedMessage());
		for (int i = 0; i < 5; i++) {
			errorMsg1.append("\r\n at:").append(stackArr[i].toString());
		}
		log.error(errorMsg1.toString());
	}
	/**
	 * 截取指定长度的字符串 
	 * @param source
	 * @param maxLength
	 * @return
	 */
	public static String trimShortLengthString(String source, int maxLength) {
		if (source == null)
			return "null";
		int printLength = Math.min(source.length(), maxLength);
		return source.substring(0, printLength);
	}
	/**
	 * FIXME 
	 * @param args 
	 * @return 返回void
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		String urlData = "{\"head\":{\"termId\":\"0000a4e67dff\",\"appVersion\":\"2.2.1\",\"sequenceCode\":1565176830190,\"requestTime\":1565176830190,\"appId\":\"hayll\",\"method\":\"login.do\"},\"body\":{\"screen\":{\"height\":1032,\"width\":1920},\"type\":1,\"method\":\"login.do\",\"deviceTypeNo\":2,\"termId\":\"0000a4e67dff\"},\"sign\":\"C83905054D9C9856C972BA7E04832BF0\"}";
		ApiParam api = JsonUtilAlibaba.getApiParam(urlData, ApiParam.class);
		boolean result = JsonUtilAlibaba.validateSign(urlData,api.getSign(),"hayll2017");
		LOG.info("解析结果:"+result);
		if(!result) {
			String sourceStr = urlData.replaceAll(api.getSign(), "hayll2017");
			// MD5加密
			String md5Str = MD5.encode(sourceStr);
			LOG.info("计算md5结果:"+md5Str+",收到md5:"+api.getSign());
		}
	}
}
